#ifndef THINK_THINK_PAGINATOR_H
#define THINK_THINK_PAGINATOR_H

static char* think_paginator =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: zhangyajun <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think;\n"
	"\n"
	"use ArrayAccess;\n"
	"use ArrayIterator;\n"
	"use Countable;\n"
	"use IteratorAggregate;\n"
	"use JsonSerializable;\n"
	"use Traversable;\n"
	"\n"
	"abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable\n"
	"{\n"
	"    /** @var bool 是否为简洁模式 */\n"
	"    protected $simple = false;\n"
	"\n"
	"    /** @var Collection 数据集 */\n"
	"    protected $items;\n"
	"\n"
	"    /** @var integer 当前页 */\n"
	"    protected $currentPage;\n"
	"\n"
	"    /** @var  integer 最后一页 */\n"
	"    protected $lastPage;\n"
	"\n"
	"    /** @var integer|null 数据总数 */\n"
	"    protected $total;\n"
	"\n"
	"    /** @var  integer 每页的数量 */\n"
	"    protected $listRows;\n"
	"\n"
	"    /** @var bool 是否有下一页 */\n"
	"    protected $hasMore;\n"
	"\n"
	"    /** @var array 一些配置 */\n"
	"    protected $options = [\n"
	"        \'var_page\' => \'page\',\n"
	"        \'path\'     => \'/\',\n"
	"        \'query\'    => [],\n"
	"        \'fragment\' => \'\',\n"
	"    ];\n"
	"\n"
	"    /** @var mixed simple模式下的下个元素 */\n"
	"    protected $nextItem;\n"
	"\n"
	"    public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])\n"
	"    {\n"
	"        $this->options = array_merge($this->options, $options);\n"
	"\n"
	"        $this->options[\'path\'] = \'/\' != $this->options[\'path\'] ? rtrim($this->options[\'path\'], \'/\') : $this->options[\'path\'];\n"
	"\n"
	"        $this->simple   = $simple;\n"
	"        $this->listRows = $listRows;\n"
	"\n"
	"        if (!$items instanceof Collection) {\n"
	"            $items = Collection::make($items);\n"
	"        }\n"
	"\n"
	"        if ($simple) {\n"
	"            $this->currentPage = $this->setCurrentPage($currentPage);\n"
	"            $this->hasMore     = count($items) > ($this->listRows);\n"
	"            if ($this->hasMore) {\n"
	"                $this->nextItem = $items->slice($this->listRows, 1);\n"
	"            }\n"
	"            $items = $items->slice(0, $this->listRows);\n"
	"        } else {\n"
	"            $this->total       = $total;\n"
	"            $this->lastPage    = (int) ceil($total / $listRows);\n"
	"            $this->currentPage = $this->setCurrentPage($currentPage);\n"
	"            $this->hasMore     = $this->currentPage < $this->lastPage;\n"
	"        }\n"
	"        $this->items = $items;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @param       $items\n"
	"     * @param       $listRows\n"
	"     * @param null  $currentPage\n"
	"     * @param bool  $simple\n"
	"     * @param null  $total\n"
	"     * @param array $options\n"
	"     * @return Paginator\n"
	"     */\n"
	"    public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])\n"
	"    {\n"
	"        return new static($items, $listRows, $currentPage, $total, $simple, $options);\n"
	"    }\n"
	"\n"
	"    protected function setCurrentPage($currentPage)\n"
	"    {\n"
	"        if (!$this->simple && $currentPage > $this->lastPage) {\n"
	"            return $this->lastPage > 0 ? $this->lastPage : 1;\n"
	"        }\n"
	"\n"
	"        return $currentPage;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取页码对应的链接\n"
	"     *\n"
	"     * @param $page\n"
	"     * @return string\n"
	"     */\n"
	"    protected function url($page)\n"
	"    {\n"
	"        if ($page <= 0) {\n"
	"            $page = 1;\n"
	"        }\n"
	"\n"
	"        if (strpos($this->options[\'path\'], \'[PAGE]\') === false) {\n"
	"            $parameters = [$this->options[\'var_page\'] => $page];\n"
	"            $path       = $this->options[\'path\'];\n"
	"        } else {\n"
	"            $parameters = [];\n"
	"            $path       = str_replace(\'[PAGE]\', $page, $this->options[\'path\']);\n"
	"        }\n"
	"        if (count($this->options[\'query\']) > 0) {\n"
	"            $parameters = array_merge($this->options[\'query\'], $parameters);\n"
	"        }\n"
	"        $url = $path;\n"
	"        if (!empty($parameters)) {\n"
	"            $url .= \'?\' . http_build_query($parameters, null, \'&\');\n"
	"        }\n"
	"        return $url . $this->buildFragment();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 自动获取当前页码\n"
	"     * @param string $varPage\n"
	"     * @param int    $default\n"
	"     * @return int\n"
	"     */\n"
	"    public static function getCurrentPage($varPage = \'page\', $default = 1)\n"
	"    {\n"
	"        $page = (int) Request::instance()->param($varPage);\n"
	"\n"
	"        if (filter_var($page, FILTER_VALIDATE_INT) !== false && $page >= 1) {\n"
	"            return $page;\n"
	"        }\n"
	"\n"
	"        return $default;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 自动获取当前的path\n"
	"     * @return string\n"
	"     */\n"
	"    public static function getCurrentPath()\n"
	"    {\n"
	"        return Request::instance()->baseUrl();\n"
	"    }\n"
	"\n"
	"    public function total()\n"
	"    {\n"
	"        if ($this->simple) {\n"
	"            throw new \\DomainException(\'not support total\');\n"
	"        }\n"
	"        return $this->total;\n"
	"    }\n"
	"\n"
	"    public function listRows()\n"
	"    {\n"
	"        return $this->listRows;\n"
	"    }\n"
	"\n"
	"    public function currentPage()\n"
	"    {\n"
	"        return $this->currentPage;\n"
	"    }\n"
	"\n"
	"    public function lastPage()\n"
	"    {\n"
	"        if ($this->simple) {\n"
	"            throw new \\DomainException(\'not support last\');\n"
	"        }\n"
	"        return $this->lastPage;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 数据是否足够分页\n"
	"     * @return boolean\n"
	"     */\n"
	"    public function hasPages()\n"
	"    {\n"
	"        return !(1 == $this->currentPage && !$this->hasMore);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 创建一组分页链接\n"
	"     *\n"
	"     * @param  int $start\n"
	"     * @param  int $end\n"
	"     * @return array\n"
	"     */\n"
	"    public function getUrlRange($start, $end)\n"
	"    {\n"
	"        $urls = [];\n"
	"\n"
	"        for ($page = $start; $page <= $end; $page++) {\n"
	"            $urls[$page] = $this->url($page);\n"
	"        }\n"
	"\n"
	"        return $urls;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置URL锚点\n"
	"     *\n"
	"     * @param  string|null $fragment\n"
	"     * @return $this\n"
	"     */\n"
	"    public function fragment($fragment)\n"
	"    {\n"
	"        $this->options[\'fragment\'] = $fragment;\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 添加URL参数\n"
	"     *\n"
	"     * @param  array|string $key\n"
	"     * @param  string|null  $value\n"
	"     * @return $this\n"
	"     */\n"
	"    public function appends($key, $value = null)\n"
	"    {\n"
	"        if (!is_array($key)) {\n"
	"            $queries = [$key => $value];\n"
	"        } else {\n"
	"            $queries = $key;\n"
	"        }\n"
	"\n"
	"        foreach ($queries as $k => $v) {\n"
	"            if ($k !== $this->options[\'var_page\']) {\n"
	"                $this->options[\'query\'][$k] = $v;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 构造锚点字符串\n"
	"     *\n"
	"     * @return string\n"
	"     */\n"
	"    protected function buildFragment()\n"
	"    {\n"
	"        return $this->options[\'fragment\'] ? \'#\' . $this->options[\'fragment\'] : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 渲染分页html\n"
	"     * @return mixed\n"
	"     */\n"
	"    abstract public function render();\n"
	"\n"
	"    public function items()\n"
	"    {\n"
	"        return $this->items->all();\n"
	"    }\n"
	"\n"
	"    public function getCollection()\n"
	"    {\n"
	"        return $this->items;\n"
	"    }\n"
	"\n"
	"    public function isEmpty()\n"
	"    {\n"
	"        return $this->items->isEmpty();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 给每个元素执行个回调\n"
	"     *\n"
	"     * @param  callable $callback\n"
	"     * @return $this\n"
	"     */\n"
	"    public function each(callable $callback)\n"
	"    {\n"
	"        foreach ($this->items as $key => $item) {\n"
	"            $result = $callback($item, $key);\n"
	"            if (false === $result) {\n"
	"                break;\n"
	"            } elseif (!is_object($item)) {\n"
	"                $this->items[$key] = $result;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Retrieve an external iterator\n"
	"     * @return Traversable An instance of an object implementing <b>Iterator</b> or\n"
	"     * <b>Traversable</b>\n"
	"     */\n"
	"    public function getIterator()\n"
	"    {\n"
	"        return new ArrayIterator($this->items->all());\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Whether a offset exists\n"
	"     * @param mixed $offset\n"
	"     * @return bool\n"
	"     */\n"
	"    public function offsetExists($offset)\n"
	"    {\n"
	"        return $this->items->offsetExists($offset);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Offset to retrieve\n"
	"     * @param mixed $offset\n"
	"     * @return mixed\n"
	"     */\n"
	"    public function offsetGet($offset)\n"
	"    {\n"
	"        return $this->items->offsetGet($offset);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Offset to set\n"
	"     * @param mixed $offset\n"
	"     * @param mixed $value\n"
	"     */\n"
	"    public function offsetSet($offset, $value)\n"
	"    {\n"
	"        $this->items->offsetSet($offset, $value);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Offset to unset\n"
	"     * @param mixed $offset\n"
	"     * @return void\n"
	"     * @since 5.0.0\n"
	"     */\n"
	"    public function offsetUnset($offset)\n"
	"    {\n"
	"        $this->items->offsetUnset($offset);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Count elements of an object\n"
	"     */\n"
	"    public function count()\n"
	"    {\n"
	"        return $this->items->count();\n"
	"    }\n"
	"\n"
	"    public function __toString()\n"
	"    {\n"
	"        return (string) $this->render();\n"
	"    }\n"
	"\n"
	"    public function toArray()\n"
	"    {\n"
	"        if ($this->simple) {\n"
	"            return [\n"
	"                \'per_page\'     => $this->listRows,\n"
	"                \'current_page\' => $this->currentPage,\n"
	"                \'has_more\'     => $this->hasMore,\n"
	"                \'next_item\'    => $this->nextItem,\n"
	"                \'data\'         => $this->items->toArray(),\n"
	"            ];\n"
	"        } else {\n"
	"            return [\n"
	"                \'total\'        => $this->total,\n"
	"                \'per_page\'     => $this->listRows,\n"
	"                \'current_page\' => $this->currentPage,\n"
	"                \'last_page\'    => $this->lastPage,\n"
	"                \'data\'         => $this->items->toArray(),\n"
	"            ];\n"
	"        }\n"
	"\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * Specify data which should be serialized to JSON\n"
	"     */\n"
	"    public function jsonSerialize()\n"
	"    {\n"
	"        return $this->toArray();\n"
	"    }\n"
	"\n"
	"    public function __call($name, $arguments)\n"
	"    {\n"
	"        $collection = $this->getCollection();\n"
	"\n"
	"        $result = call_user_func_array([$collection, $name], $arguments);\n"
	"\n"
	"        if ($result === $collection) {\n"
	"            return $this;\n"
	"        }\n"
	"\n"
	"        return $result;\n"
	"    }\n"
	"\n"
	"}\n"
	"\n"
;
#endif